In [ ]:
#import all the libraries needed
from imports import *
# import my functions
from function_store import *
# Define the path to the directories containing the VNA data
directory_1 = ('/Users/horatiocox/Desktop/VNA_Analysis/mag_angle_260424/')
directory_3 = ('/Users/horatiocox/Desktop/VNA_Analysis/CPW_mem_oscillator_220524/Oscillator/')
# Import the data from the VNA files
s2p_files_1 = import_data(directory_1)
s2p_files_3 = import_data(directory_3)
# Remove duplicate frequency points from all the thru data to prevent errors with skrf functions
s2p_files_1 = duplicate_check(s2p_files_1)
s2p_files_3 = duplicate_check(s2p_files_3)
1 run1_r0c0_thru Wafer0_r0_c0_ISS_thru_LRM+_1.S2P 2 run2_rNonecNone_thru ISS_thru_LRRM_1.S2P 3 run3_r10c1_thru Wafer2_r10_c1_thru_1.S2P 4 run4_r10c13_thrunotaper Wafer2_r10_c13_thrunotaper_1.S2P 5 run5_r10c5_open Wafer2_r10_c5_open_1.S2P 6 run6_r10c9_opensig Wafer2_r10_c9_opensig_1.S2P 7 run7_r10c11_short Wafer2_r10_c11_short_1.S2P 8 run8_r1c2_pristine Wafer2_r1_c2_pristine_1.S2P 9 run9_r1c2_pristine Wafer2_r1_c2_pristine 2_1.S2P 10 run10_r1c3_pristine Wafer2_r1_c3_pristine_1.S2P 11 run11_r1c4_pristine Wafer2_r1_c4_pristine_1.S2P 12 run12_r1c5_pristine Wafer2_r1_c5_pristine_1.S2P 13 run13_r1c6_pristine Wafer2_r1_c6_pristine_1.S2P 14 run14_r1c7_pristine Wafer2_r1_c7_pristine_1.S2P 15 run15_r1c7_pristine Wafer2_r1_c7_pristine 2_1.S2P 16 run16_r1c8_pristine Wafer2_r1_c8_pristine_1.S2P 17 run17_r1c9_pristine Wafer2_r1_c9_pristine_1.S2P 18 run18_rNonecNone_thru ISS_thru_LRM+_log_1.S2P 19 run19_r1c2_pristine Wafer2_r1_c2_pristine_log_1.S2P 20 run20_r1c3_pristine Wafer2_r1_c3_pristine_log_1.S2P 21 run21_r1c4_pristine Wafer2_r1_c4_pristine_log_1.S2P 22 run22_r1c5_pristine Wafer2_r1_c5_pristine_log_1.S2P 23 run23_r1c6_pristine Wafer2_r1_c6_pristine_log_1.S2P 24 run24_r1c7_pristine Wafer2_r1_c7_pristine_log_1.S2P 25 run25_r1c8_pristine Wafer2_r1_c8_pristine_log_1.S2P 26 run26_r1c9_pristine Wafer2_r1_c9_pristine_log_1.S2P 27 run27_r1c9_smallform Wafer2_r1_c9_smallform_log_1.S2P 28 run28_r1c8_smallform Wafer2_r1_c8_smallform_log_1.S2P 29 run29_r1c7_smallform Wafer2_r1_c7_smallform_log_1.S2P 30 run30_r1c6_smallform Wafer2_r1_c6_smallform_log_1.S2P 31 run31_r1c5_smallform Wafer2_r1_c5_smallform_log_1.S2P 32 run32_r1c4_smallform Wafer2_r1_c4_smallform_log_1.S2P 33 run33_r1c3_smallform Wafer2_r1_c3_smallform_log_1.S2P 34 run34_r1c2_smallform Wafer2_r1_c2_smallform_log_1.S2P 35 run35_r1c9_fullform Wafer2_r1_c9_fullform_log_1.S2P 36 run36_r1c8_fullform Wafer2_r1_c8_fullform_log_1.S2P 37 run37_r1c7_fullform Wafer2_r1_c7_fullform_log_1.S2P 38 run38_r1c7_fullform Wafer2_r1_c7_fullform_log 2_1.S2P 39 run39_r1c6_fullform Wafer2_r1_c6_fullform_log_1.S2P 40 run40_r1c5_fullform Wafer2_r1_c5_fullform_log_1.S2P 41 run41_r1c4_fullform Wafer2_r1_c4_fullform_log_1.S2P 42 run42_r1c3_fullform Wafer2_r1_c3_fullform_log_1.S2P 43 run43_r1c2_fullform Wafer2_r1_c2_fullform_log_1.S2P 1 run1_r2c1_thru Wafer3_r2_c1_thru.S2P 2 run2_r2c2_open Wafer3_r2_c2_open.S2P 3 run3_r2c2_opensig Wafer3_r2_c2_opensignal.S2P 4 run4_r2c3_short Wafer3_r2_c3_short.S2P 5 run5_r2c4_pristine Wafer3_r2_c4_pristine.S2P 6 run6_r2c4_pristine Wafer3_r2_c4_pristine 2.S2P 7 run7_r2c4_pristine Wafer3_r2_c4_pristine 3.S2P 8 run8_r2c4_pristine Wafer3_r2_c4_pristine 4.S2P 9 run9_r2c4_pristine Wafer3_r2_c4_pristine 5.S2P 10 run10_r2c5_pristine Wafer3_r2_c5_pristine.S2P 11 run11_r3c1_thru Wafer3_r3_c1_thru.S2P 12 run12_r3c2_open Wafer3_r3_c2_open.S2P 13 run13_r3c3_opensig Wafer3_r3_c3_opensignal.S2P 14 run14_r3c4_short Wafer3_r3_c4_short.S2P 15 run15_r3c5_pristine Wafer3_r3_c5_pristine.S2P 16 run16_r3c5_pristine Wafer3_r3_c5_pristine 2.S2P 17 run17_r3c6_pristine Wafer3_r3_c6_pristine.S2P 18 run18_r3c6_pristine Wafer3_r3_c6_pristine 2.S2P 19 run19_r3c6_pristine Wafer3_r3_c6_pristine 3.S2P 20 run20_r3c6_pristine Wafer3_r3_c6_pristine_pos0.0dc.S2P 21 run21_r3c6_pristine Wafer3_r3_c6_pristine_pos10dc.S2P 22 run22_r3c6_pristine Wafer3_r3_c6_pristine_pos20dc.S2P 23 run23_r3c6_pristine Wafer3_r3_c6_pristine_pos25dc.S2P 24 run24_r3c6_pristine Wafer3_r3_c6_pristine_pos27dc.S2P 25 run25_r3c6_pristine Wafer3_r3_c6_pristine_pos29dc.S2P 26 run26_r3c6_pristine Wafer3_r3_c6_pristine_pos31dc.S2P 27 run27_r2c5_pristine Wafer3_r2_c5_pristine_pos0.0dc.S2P 28 run28_r2c5_pristine Wafer3_r2_c5_pristine_pos1.0dc.S2P 29 run29_r2c5_pristine Wafer3_r2_c5_pristine_pos10dc.S2P 30 run30_r2c5_pristine Wafer3_r2_c5_pristine_pos15dc.S2P 31 run31_r2c5_pristine Wafer3_r2_c5_pristine_pos20dc.S2P 32 run32_r2c5_pristine Wafer3_r2_c5_pristine_pos25dc.S2P 33 run33_r2c5_pristine Wafer3_r2_c5_pristine_pos30dc.S2P 34 run34_r2c5_pristine Wafer3_r2_c5_pristine_pos35dc.S2P 35 run35_r2c5_pristine Wafer3_r2_c5_pristine_pos40dc.S2P
CPW Memristor 1 - Bias T Experiment¶
Import Data¶
In [ ]:
# Define the path to the directory containing the VNA data
directory_2 = ('/Users/horatiocox/Desktop/VNA_Analysis/CPW_mem_oscillator_220524/Memristor/');
# Import the data from the VNA files
s2p_files_2 = import_data(directory_2);
# Remove duplicate frequency points from all the thru data to prevent errors with skrf functions
s2p_files_2 = duplicate_check(s2p_files_2);
1 run1_r0c0_thru Wafer0_r0_c0_ISS_thru_LRM+.S2P 2 run2_r10c1_thru Wafer2_r10_c1_thru.S2P 3 run3_r10c2_thru Wafer2_r10_c2_thru.S2P 4 run4_r10c3_thru Wafer2_r10_c3_thru.S2P 5 run5_r10c4_thru Wafer2_r10_c4_thru.S2P 6 run6_r10c5_open Wafer2_r10_c5_open.S2P 7 run7_r10c6_open Wafer2_r10_c6_open.S2P 8 run8_r10c7_opennarrow Wafer2_r10_c7_opennarrow.S2P 9 run9_r10c8_openverynarrow Wafer2_r10_c8_openverynarrow.S2P 10 run10_r10c9_opensig Wafer2_r10_c9_opensig.S2P 11 run11_r10c10_opensig Wafer2_r10_c10_opensig.S2P 12 run12_r10c12_short Wafer2_r10_c12_short.S2P 13 run13_r10c13_short Wafer2_r10_c13_short.S2P 14 run14_r10c14_thrunotaper Wafer2_r10_c14_thrunotaper.S2P 15 run15_r10c15_thrunotaper Wafer2_r10_c15_thrunotaper.S2P 16 run16_r10c16_opennotaper Wafer2_r10_c16_opennotaper.S2P 17 run17_r10c17_opennotaper Wafer2_r10_c17_opennotaper.S2P 18 run18_r10c18_opensignotaper Wafer2_r10_c18_opensignotaper.S2P 19 run19_r10c19_opensignotaper Wafer2_r10_c19_opensignotaper.S2P 20 run20_r10c20_shortnotaper Wafer2_r10_c20_shortnotaper.S2P 21 run21_r10c21_shortnotaper Wafer2_r10_c21_shortnotaper.S2P 22 run22_r1c2_formed Wafer2_r1_c2_formedpreviously.S2P 23 run23_r2c1_pristine Wafer2_r2_c1_pristine.S2P 24 run24_r2c1_pristine Wafer2_r2_c1_pristine_pos0.2dc.S2P 25 run25_r2c1_pristine Wafer2_r2_c1_pristine_pos0.4dc.S2P 26 run26_r2c1_pristine Wafer2_r2_c1_pristine_pos0.6dc.S2P 27 run27_r2c1_pristine Wafer2_r2_c1_pristine_pos0.8dc.S2P 28 run28_r2c1_pristine Wafer2_r2_c1_pristine_pos1.0dc.S2P 29 run29_r2c1_pristine Wafer2_r2_c1_pristine_pos1.2dc.S2P 30 run30_r2c1_pristine Wafer2_r2_c1_pristine_pos1.4dc.S2P 31 run31_r2c1_pristine Wafer2_r2_c1_pristine_pos1.6dc.S2P 32 run32_r2c1_pristine Wafer2_r2_c1_pristine_neg0.2dc.S2P 33 run33_r2c1_pristine Wafer2_r2_c1_pristine_neg0.4dc.S2P 34 run34_r2c1_pristine Wafer2_r2_c1_pristine_neg0.6dc.S2P 35 run35_r2c1_pristine Wafer2_r2_c1_pristine_neg0.8dc.S2P 36 run36_r2c1_pristine Wafer2_r2_c1_pristine_neg1.0dc.S2P 37 run37_r2c1_pristine Wafer2_r2_c1_pristine_neg1.2dc.S2P 38 run38_r2c1_pristine Wafer2_r2_c1_pristine_neg1.4dc.S2P 39 run39_r2c1_pristine Wafer2_r2_c1_pristine_neg1.6dc.S2P 40 run40_r2c1_pristine Wafer2_r2_c1_pristine_neg1.8dc.S2P 41 run41_r2c1_pristine Wafer2_r2_c1_pristine_neg2.0dc.S2P 42 run42_r2c1_formed Wafer2_r2_c1_formed_0dc.S2P 43 run43_r2c1_formed Wafer2_r2_c1_formed_pos0.0dc.S2P 44 run44_r2c1_formed Wafer2_r2_c1_formed_pos0.4dc.S2P 45 run45_r2c1_formed Wafer2_r2_c1_formed_pos0.8dc.S2P 46 run46_r2c1_formed Wafer2_r2_c1_formed_pos1.2dc.S2P 47 run47_r2c1_formed Wafer2_r2_c1_formed_pos1.4dc.S2P 48 run48_r2c1_formed Wafer2_r2_c1_formed_neg0.4dc.S2P 49 run49_r2c1_formed Wafer2_r2_c1_formed_neg0.8dc.S2P 50 run50_r2c1_formed Wafer2_r2_c1_formed_neg1.2dc.S2P 51 run51_r2c1_formed Wafer2_r2_c1_formed_neg1.2dc_repeat.S2P 52 run52_r2c1_formed Wafer2_r2_c1_formed_neg1.2dc_repeat2.S2P 53 run53_r2c1_formed Wafer2_r2_c1_formed_neg1.2dc_repeat3.S2P 54 run54_r2c1_formed Wafer2_r2_c1_formed_neg1.2dc_repeat4.S2P 55 run55_r2c1_formed Wafer2_r2_c1_formed_neg0dc_repeat5.S2P 56 run56_r2c1_set Wafer2_r2_c1_reset.S2P 57 run57_r2c1_set Wafer2_r2_c1_set.S2P 58 run58_r2c1_set Wafer2_r2_c1_set2.S2P 59 run59_r2c1_set Wafer2_r2_c1_set3.S2P 60 run60_r2c1_set Wafer2_r2_c1_reset2.S2P 61 run61_r2c1_set Wafer2_r2_c1_set4.S2P 62 run62_r2c1_set Wafer2_r2_c1_set5.S2P 63 run63_r2c1_set Wafer2_r2_c1_set6.S2P 64 run64_r2c1_set Wafer2_r2_c1_reset3.S2P 65 run65_r2c1_set Wafer2_r2_c1_set7.S2P 66 run66_r2c1_set Wafer2_r2_c1_set8.S2P 67 run67_r2c1_set Wafer2_r2_c1_reset4.S2P 68 run68_r2c1_set Wafer2_r2_c1_set9.S2P
Plot Raw S-Params¶
In [ ]:
# Select ISS thru, on wafer thru, on wafer open and compare in one color to a pristine/formed/reset device in another color
raw_data = subgen(s2p_files_2, run_nums =[[1,2,6,], [23,42,56] ] )
# Plot the data
f = plt.figure(figsize=(20,10),dpi=200)
gs = f.add_gridspec(2, 2)
ax = f.add_subplot(gs[0, 0])
ax1 = f.add_subplot(gs[0, 1])
ax2 = f.add_subplot(gs[1, 0])
ax3 = f.add_subplot(gs[1, 1])
sub_plot(ax=ax, dev_subset=raw_data, plot_type=['s_db'], log_x=False, m_port=[2], n_port=[1], deembed_data=False,
y_range = [-55,0],x_range='0.01-20ghz')
sub_plot(ax=ax1, dev_subset=raw_data, plot_type=['s_deg'], log_x=False, m_port=[2], n_port=[1], deembed_data=False,
y_range=[-50,100], x_range='0.01-20ghz')
sub_plot(ax=ax2, dev_subset=raw_data, plot_type=['s_db'], log_x=False, m_port=[1], n_port=[1], deembed_data=False,
y_range = [-55,0],x_range='0.01-20ghz')
sub_plot(ax=ax3, dev_subset=raw_data, plot_type=['s_deg'], log_x=False, m_port=[1], n_port=[1], deembed_data=False,
y_range=[-100,0], x_range='0.01-20ghz')
plt.show()
Now Focusing in on the S21¶
In [ ]:
f = plt.figure(figsize=(20,5),dpi=200)
gs = f.add_gridspec(1, 2)
ax = f.add_subplot(gs[0, 0])
ax1 = f.add_subplot(gs[0, 1])
sub_plot(dev_subset=raw_data, plot_type=['s_db'], log_x=False, m_port=[2], n_port=[1], deembed_data=False,
y_range = [-2,0],x_range='0.01-20ghz', ax=ax)
sub_plot(dev_subset=raw_data, plot_type=['s_deg'], log_x=False, m_port=[2], n_port=[1], deembed_data=False,
y_range=[-50,100], x_range='0.01-20ghz', ax=ax1)
plt.show()
Initial Analysis¶
- The ISS shows almost no loss for S21 as expected
- The on wafer CPW thru has quite a low loss
- The On wafer Thru/Memristor have an oscillation "noise" which is very significant and likely due to an impedance mismatch
- This noise is greater than the difference between pristine/formed/reset states
- It will need to be removed before any clear difference between memristor states can be determined
Open Short De-embedding¶
In [ ]:
#-------------------Grouping-------------------
# Select the On Wafer Calibration files to be used
ISS_thru = [s for s in s2p_files_2 if s.state == 'thru' and s.wafer_number == 0]
cal_thru = [s for s in s2p_files_2 if s.state == 'thru' and s.wafer_number != 0]
cal_open = [s for s in s2p_files_2 if s.state == 'open' or s.state == 'opensig']
cal_short = [s for s in s2p_files_2 if s.state == 'short']
#-------------------De-Embedding-------------------
print('open_short_thru',len(cal_open),len(cal_short),len(cal_thru))
#whether to plot the de-embedding results
OS = calibration_OS(cal_open, cal_short, cal_thru, plot_cal = False) #calibration object outputted from all the on wafer measurements
TX = calibration_2x(cal_thru, plot_cal = False) #calibration object outputted from all the on wafer measurements
# Plot the data with the deembeding applied and compare to the raw data
f = plt.figure(figsize=(20,8),dpi=200)
gs = f.add_gridspec(1, 2)
ax = f.add_subplot(gs[0, 0])
ax1 = f.add_subplot(gs[0, 1])
# deembeding is applied with an argument in the function and the deembeding object desired is passed to the function
sub_plot(ax=ax, dev_subset=raw_data, plot_type=['s_mag'], log_x=False, m_port=[2], n_port=[1], deembed_data=False,
y_range = [0.8,1.05],x_range='0.01-20ghz', cal_in = [])
sub_plot(ax=ax1, dev_subset=raw_data, plot_type=['s_mag'], log_x=False, m_port=[2], n_port=[1], deembed_data=True,
y_range=[0.8,1.05], x_range='0.01-20ghz',cal_in = OS)
plt.show()
open_short_thru 4 2 4 [29493.25017913594, 29493.828865204905, 29493.097293820058, 29492.936062208333, 29489.754914854297, 29493.548249662417, 29489.8297148353, 29490.92647900279] Best de-embedding protocol: dm[4] = 29489.754914854297, worst:dm[1] = 29493.828865204905 [22093.334805985014, 22166.101440143848, 22111.505466789735, 22149.911859675216] Best de-embedding protocol: dm[0] = 22093.334805985014, worst:dm[1] = 22166.101440143848
Notes¶
- The de-embedding improves the thru device measurably
- Definitely shifts the memristor so more signal going through for s21
- Though the on wafer thru now averages around s21 = 1 - the noise remains just as large!
- The noise continues to prevent any effective comparison between the memristors
2x Thru De-embedding¶
In [ ]:
#-------------------De-Embedding-------------------
TX = calibration_2x(cal_thru, plot_cal = False) #calibration object outputted from all the on wafer measurements
# Plot the data with the deembeding applied and compare to the raw data
f = plt.figure(figsize=(20,8),dpi=200)
gs = f.add_gridspec(1, 2)
ax = f.add_subplot(gs[0, 0])
ax1 = f.add_subplot(gs[0, 1])
# deembeding is applied with an argument in the function and the deembeding object desired is passed to the function
sub_plot(ax=ax, dev_subset=raw_data, plot_type=['s_mag'], log_x=False, m_port=[2], n_port=[1], deembed_data=False,
y_range = [0.8,1.05],x_range='0.01-20ghz', cal_in = [])
sub_plot(ax=ax1, dev_subset=raw_data, plot_type=['s_mag'], log_x=False, m_port=[2], n_port=[1], deembed_data=True,
y_range=[0.8,1.05], x_range='0.01-20ghz',cal_in = TX)
plt.show()
[22093.334805985014, 22166.101440143848, 22111.505466789735, 22149.911859675216] Best de-embedding protocol: dm[0] = 22093.334805985014, worst:dm[1] = 22166.101440143848
Notes¶
- Again de-embedding improves the thru device measurably
- Again Definitely shifts the memristor so more signal going through for s21
- Again Though the on wafer thru now averages around s21 = 1 - the noise remains just as large!
- Difference is that the 2x appears to be better - though it uses the thru so comparison on a thru device probaly not representative
FFT filtering to remove oscillations¶
In [ ]:
# Demo for the on-wafer thru device
thru_filt_test = [copy.deepcopy(cal_thru[0])]
# Select bandstop frequency components
threshold_values = [[1.8e-8,2.2e-8],[5.9e-8,6.15e-8],[3.9e-8,4.05e-8],[2.9e-8,3.05e-8],[7.95e-8,8.05e-8],[6.45e-8,6.55e-8],[6.96e-8,7.06e-8]]
# Apply the FFT, filter out components then IFFT
s2p_test_filt = fourier_filter(thru_filt_test, threshold = threshold_values,t_window = 0.02)
Notes¶
- t_window applies a tukey window to the data before applying the FFT - this prevents spectral leakage
- This sacrifices some of the higher and lower frequencies but massively improves the quality of the filtered data
- a higher t_window value applies a sharper window - so I have kept it as small as possible
In [ ]:
# Plot the data with and without FFT filtering
f = plt.figure(figsize=(20,8),dpi=200)
gs = f.add_gridspec(1, 2)
ax = f.add_subplot(gs[0, 0])
ax1 = f.add_subplot(gs[0, 1])
sub_plot(ax=ax, dev_subset=[[cal_thru[0]]], plot_type=['s_mag'], log_x=False, m_port=[2], n_port=[1], deembed_data=False,
y_range = [0.95,1.0],x_range='0.01-20ghz')
sub_plot(ax=ax1, dev_subset= [s2p_test_filt], plot_type=['s_mag'], log_x=False, m_port=[2], n_port=[1], deembed_data=False,
y_range=[0.95,1.0], x_range='0.01-20ghz')
plt.show()
De-embedding on FFT filtered data¶
In [ ]:
#### Need to re-do the calibration on fully FFT filtered data before applying it!
s2p_files_2_filt = copy.deepcopy(s2p_files_2)
# Select bandstop frequency components
threshold_values = [[1.8e-8,2.2e-8],[5.9e-8,6.15e-8],[3.9e-8,4.05e-8],[2.9e-8,3.05e-8],[7.95e-8,8.05e-8],[6.45e-8,6.55e-8],[6.96e-8,7.06e-8]]
# Apply the FFT, filter out components then IFFT
s2p_files_2_filt = fourier_filter(s2p_files_2_filt, threshold = threshold_values,t_window = 0.02) #apply to deepcopy to avoid modifying the original data
#-------------------Grouping-------------------
# Select the On Wafer Calibration files to be used
ISS_thru_filt = [s for s in s2p_files_2_filt if s.state == 'thru' and s.wafer_number == 0]
cal_thru_filt = [s for s in s2p_files_2_filt if s.state == 'thru' and s.wafer_number != 0]
cal_open_filt = [s for s in s2p_files_2_filt if s.state == 'open' or s.state == 'opensig']
cal_short_filt = [s for s in s2p_files_2_filt if s.state == 'short']
#-------------------De-Embedding-------------------
OS_filt = calibration_OS(cal_open_filt, cal_short_filt, cal_thru_filt, plot_cal = False) #calibration object outputted from all the on wafer measurements
TX_filt = calibration_2x(cal_thru_filt, plot_cal = False) #calibration object outputted from all the on wafer measurements
[28353.392561250494, 28370.406436998805, 28354.071596680602, 28371.07807926913, 28353.673722217638, 28370.669529166313, 28354.12137072636, 28371.112750655735] Best de-embedding protocol: dm[0] = 28353.392561250494, worst:dm[7] = 28371.112750655735 [21952.43768002349, 21978.870347280088, 21979.473121506657, 21990.126025888083] Best de-embedding protocol: dm[0] = 21952.43768002349, worst:dm[3] = 21990.126025888083
In [ ]:
# Plot the data with and without FFT filtering
f = plt.figure(figsize=(20,12),dpi=200)
gs = f.add_gridspec(3, 1)
ax = f.add_subplot(gs[0, 0])
ax1 = f.add_subplot(gs[1, 0])
ax2 = f.add_subplot(gs[2, 0])
#FFT only
sub_plot(ax=ax, dev_subset=[s2p_test_filt], plot_type=['s_mag'], log_x=False, m_port=[2], n_port=[1], deembed_data=False,
y_range = [0.95,1.02],x_range='0.01-20ghz')
# FFT and OS deembeding
sub_plot(ax=ax1, dev_subset=[s2p_test_filt], plot_type=['s_mag'], log_x=False, m_port=[2], n_port=[1], deembed_data=True,
y_range = [0.95,1.02],x_range='0.01-20ghz',cal_in = OS_filt)
# FFT and 2X deembeding
sub_plot(ax=ax2, dev_subset= [s2p_test_filt], plot_type=['s_mag'], log_x=False, m_port=[2], n_port=[1], deembed_data=True,
y_range=[0.95,1.02], x_range='0.01-20ghz',cal_in = TX_filt)
plt.show()
FFT filtering on De-embedded data¶
In [ ]:
# Go through and de-embed all data
sp2_files_2_OS = copy.deepcopy(s2p_files_2)
sp2_files_2_TX = copy.deepcopy(s2p_files_2)
for f in sp2_files_2_OS:
f.network = OS.deembed(f.network)
for f in sp2_files_2_TX:
f.network = TX.deembed(f.network)
# Extract the on wafer thru
thru_filt_OS = [copy.deepcopy(sp2_files_2_OS[1])]
# Select bandstop frequency components
threshold_values = [[1.8e-8,2.2e-8],[5.9e-8,6.15e-8],[3.9e-8,4.05e-8],[2.9e-8,3.05e-8],[7.95e-8,8.05e-8],[6.45e-8,6.55e-8],[6.96e-8,7.06e-8]]
# Apply the FFT, filter out components then IFFT
s2p_2_OS_filt = fourier_filter(thru_filt_OS, threshold = threshold_values,t_window = 0.02)
# Extract the on wafer thru
thru_filt_TX = [copy.deepcopy(sp2_files_2_TX[1])]
# Select bandstop frequency components
threshold_values = [[1.8e-8,2.2e-8],[5.9e-8,6.15e-8],[3.9e-8,4.05e-8],[2.9e-8,3.05e-8],[7.95e-8,8.05e-8],[6.45e-8,6.55e-8],[6.96e-8,7.06e-8]]
# Apply the FFT, filter out components then IFFT
s2p_2_TX_filt = fourier_filter(thru_filt_TX, threshold = threshold_values,t_window = 0.02)
In [ ]:
# Plot the data with and without FFT filtering
f = plt.figure(figsize=(20,8),dpi=200)
gs = f.add_gridspec(1, 2)
ax = f.add_subplot(gs[0, 0])
ax1 = f.add_subplot(gs[0, 1])
sub_plot(ax=ax, dev_subset=[s2p_2_OS_filt], plot_type=['s_mag'], log_x=False, m_port=[2], n_port=[1], deembed_data=False,
y_range = [0.95,1.05],x_range='0.01-20ghz')
sub_plot(ax=ax1, dev_subset= [s2p_2_TX_filt], plot_type=['s_mag'], log_x=False, m_port=[2], n_port=[1], deembed_data=False,
y_range=[0.95,1.05], x_range='0.01-20ghz')
plt.show()
Notes¶
- It is much noisier if you do the FFT on the de-embedded data
- seems to be better to FFT the data, filter then apply the de-embedding
- Though the 2x de-embedding appears perfect, this is deembeding the thru device directly from itself
- as the same device is used for the de-embedding and reference
- unfortunately the quality is not the same when applied to memristors
Best so Far on Memristor¶
FFT all the data, then do the calibration on the FFT filtered data, then do the de-embedding 2x
In [ ]:
# Select the data from the already FFT filtered fulll data set
filtered_memristor = subgen(s2p_files_2_filt, run_nums =[[1,2,6,], [23,42,56] ] )
raw_data = subgen(s2p_files_2, run_nums =[[1,2,6,], [23,42,56] ] )
# Plot the FFT data with and without de embedding
f = plt.figure(figsize=(60,30),dpi=200)
gs = f.add_gridspec(3, 5)
ax = f.add_subplot(gs[0, 0])
ax1 = f.add_subplot(gs[0, 1])
sub_plot(ax=ax, dev_subset = raw_data, plot_type=['s_mag'], log_x=False, m_port=[2], n_port=[1], deembed_data=False,
y_range = [0.7,1.0],x_range='0.01-20ghz')
# Apply the filtered TX deembeding to the filtered data
sub_plot(ax=ax1, dev_subset = filtered_memristor, plot_type=['s_mag'], log_x=False, m_port=[2], n_port=[1], deembed_data=True,
y_range=[0.7,1.0], x_range='0.01-20ghz',cal_in = TX_filt)
plt.show()
Notes¶
- Overall a large improvement in both reducing the noise and increasing the S21 transmission
- Now we can compare memristor states
Memristor state comparison¶
In [ ]:
# Select the data from the already FFT filtered fulll data set
run_n =[[1,2,3,4,5,6], [56,60,64,67], [57,58,59,61,62,63,65,66,68] ]
filtered_memristor = subgen(s2p_files_2_filt, run_nums = run_n )
raw_data = subgen(s2p_files_2, run_nums = run_n )
# Plot the FFT data with and without de embedding
f = plt.figure(figsize=(20,8),dpi=200)
gs = f.add_gridspec(1, 2)
ax = f.add_subplot(gs[0, 0])
ax1 = f.add_subplot(gs[0, 1])
sub_plot(ax=ax, dev_subset = raw_data, plot_type=['s_mag'], log_x=True, m_port=[2], n_port=[1], deembed_data=False,
y_range = None,x_range='0.1-20ghz')
# Apply the filtered TX deembeding to the filtered data
sub_plot(ax=ax1, dev_subset = filtered_memristor, plot_type=['s_mag'], log_x=True, m_port=[2], n_port=[1], deembed_data=True,
y_range=None, x_range='0.1-20ghz',cal_in = OS_filt)
plt.show()
Notes¶
- Set is where we see the largest variation due to big differences in the resistance of the LRS
- potentially filamental vs interface based switching
- RESET into the HRS yields a much tighter range of values
- Is still a clear variation in the HRS
- A significant finding here is not only that the resistance switching is visible at the lower frequencies but that at higher frequencies there are clear differences in the S-params which I believe indicates differences in the permittivity/capacitance of devices
- Clearly these devices can be used to modulate microwave signals across a broad range of frequencies which is a good start
Look At Power inputz and other params¶
In [ ]:
# Select the data from the already FFT filtered fulll data set
run_n =[[1,2,3,4,5,6], [56,60,64,67], [57,58,59,61,62,63,65,66,68] ]
filtered_memristor = subgen(s2p_files_2_filt, run_nums = run_n )
raw_data = subgen(s2p_files_2, run_nums = run_n )
# Plot the FFT data with and without de embedding
f = plt.figure(figsize=(20,8),dpi=200)
gs = f.add_gridspec(1, 2)
ax = f.add_subplot(gs[0, 0])
ax1 = f.add_subplot(gs[0, 1])
#Plotting and comparing only the filtered data now
sub_plot(ax=ax, dev_subset = filtered_memristor, plot_type=['inputz'], log_x=True, m_port=[2], n_port=[1], deembed_data=False,
y_range = [0,200],x_range='0.1-20ghz',cal_in = OS_filt)
# Apply the filtered TX deembeding to the filtered data
sub_plot(ax=ax1, dev_subset = filtered_memristor, plot_type=['power'], log_x=False, m_port=[2], n_port=[1], deembed_data=False,
y_range=[0.8,0.95], x_range='0.1-20ghz',cal_in = OS_filt)
plt.show()
Normalize the input impedance and s parameters to a pristine reference measurement¶
In [ ]:
# Select the data from the already FFT filtered fulll data set
run_n =[ [23,56,60,64,67], [23,57,58,59,61,62,63,65,66,68] ]
filtered_memristor = subgen(s2p_files_2_filt, run_nums = run_n )
raw_data = subgen(s2p_files_2, run_nums = run_n )
# Plot the FFT data with and without de embedding
f = plt.figure(figsize=(20,8),dpi=200)
gs = f.add_gridspec(1, 2)
ax = f.add_subplot(gs[0, 0])
ax1 = f.add_subplot(gs[0, 1])
#Plotting and comparing only the filtered data now
sub_plot(ax=ax, dev_subset = filtered_memristor, plot_type=['znorm'], log_x=False, m_port=[2], n_port=[1], deembed_data=False,
y_range = [0.9,1.1],x_range='0.1-20ghz',cal_in = OS_filt)
# Apply the filtered TX deembeding to the filtered data
sub_plot(ax=ax1, dev_subset = filtered_memristor, plot_type=['snorm'], log_x=False, m_port=[1], n_port=[2], deembed_data=False,
y_range=[0.98,1.005], x_range='0.1-20ghz',cal_in = OS_filt)
plt.show()
Now let us compare the pristine DC bias measurements in the s-norm mode¶
In [ ]:
# Select the data from the already FFT filtered fulll data set
run_n =[ [23,56,60,64,67], [31,27,23,35,39,41],[23,57,58,59,61,62,63,65,66,68] ]
run_n2 = [ [1], [31,27,23,35,39,41]]
run_n3 = [ [23,56,60,64,67], [31,27,23,35,39,41],[27,57,58,59,61,62,63,65,66,68] ]
filtered_memristor = subgen(s2p_files_2_filt, run_nums = run_n )
filtered_memristor2 = subgen(s2p_files_2_filt, run_nums = run_n2 )
filtered_memristor3 = subgen(s2p_files_2_filt, run_nums = run_n3 )
# Plot the FFT data with and without de embedding
f = plt.figure(figsize=(15,10),dpi=200)
gs = f.add_gridspec(3, 1)
ax = f.add_subplot(gs[0, 0])
ax1 = f.add_subplot(gs[1, 0])
ax2 = f.add_subplot(gs[2, 0])
# Comparing the DC biases
sub_plot(ax=ax, dev_subset = filtered_memristor2, plot_type=['snorm'], log_x=False, m_port=[2], n_port=[1], deembed_data=False,
y_range = [0.997,1.002],x_range='0.1-20ghz',cal_in = OS_filt)
# Comparing DC biases with switched states
sub_plot(ax=ax1, dev_subset = filtered_memristor, plot_type=['snorm'], log_x=False, m_port=[1], n_port=[2], deembed_data=False,
y_range=[0.98,1.005], x_range='0.1-20ghz',cal_in = OS_filt)
# DC biases, switched states but using a different 'pristine' object to normalise
sub_plot(ax=ax2, dev_subset = filtered_memristor3, plot_type=['snorm'], log_x=False, m_port=[1], n_port=[2], deembed_data=False,
y_range=[0.98,1.005], x_range='0.1-20ghz',cal_in = OS_filt)
plt.show()
Notes¶
- In plot 1 we can see that the DC biasing gives a slight shift in the s-params
- Though this is incredibly slight and at the limit of the noise
- In plot 2 the DC bias are shown in blue-green with the HRS in greys and the LRS in yellow-orange
- Plot 3 is the same as plot 2 but the normalisation device is changed from pristine, to pristine_DC=0.2V
- The reason for this is that I wanted to see if the small peaks are a product of normalisation or a consistent difference between pristine/formed devices
- It appears that there are small localised frequency variations between pristine/formed
- These may be real features of interest if consistent across other devices and not a product of data processing
Comparing SET(LRS)/RESET(HRS)¶
In [ ]:
# Select the data from the already FFT filtered fulll data set
run_n =[ [23,56,60,64,67],[23,57,58,59,61,62,63,65,66,68] ]
#pairs of set/reset to compare
run_n2 = [ [23,56],[56,57],[60,58],[64,59],[67,61] ]
filtered_memristor = subgen(s2p_files_2_filt, run_nums = run_n )
filtered_memristor2 = subgen(s2p_files_2_filt, run_nums = run_n2 )
# Plot the FFT data with and without de embedding
f = plt.figure(figsize=(15,10),dpi=200)
gs = f.add_gridspec(2, 1)
ax = f.add_subplot(gs[0, 0])
ax1 = f.add_subplot(gs[1, 0])
# Comparing all SET/RESET devices
sub_plot(ax=ax, dev_subset = filtered_memristor, plot_type=['snorm'], log_x=False, m_port=[2], n_port=[1], deembed_data=False,
y_range = [0.98,1.005],x_range='0.1-20ghz',cal_in = OS_filt)
# Comparing SET/RESET device pairs
sub_plot(ax=ax1, dev_subset = filtered_memristor2, plot_type=['snorm'], log_x=False, m_port=[1], n_port=[2], deembed_data=False,
y_range=[0.995,1.002], x_range='0.1-20ghz',cal_in = OS_filt)
plt.show()
Notes¶
- Generally the SET(LRS have lower s21 reflecting lower r? but also changes in c?)
- the first pair of data in grey are pristine vs reset and the spike at 10GHz and a few other places are visible
- These spikes arent visible from SET to RESET implying that if these spikes are created in the forming they are not altered in the SET/RESET process
Rest of Data¶
In [ ]:
# # Step 0 - check fourier filter on a thru calibration and a device to compare the frequency spikes
# threshold_values = [[1.8e-8,2.2e-8],[5.9e-8,6.15e-8],[3.9e-8,4.05e-8],[2.9e-8,3.05e-8],[7.95e-8,8.05e-8],[6.45e-8,6.55e-8],[6.96e-8,7.06e-8]]
# ISS_filt_test = [copy.deepcopy(s2p_files[0])]
# s2p_filt = fourier_filter(ISS_filt_test, threshold = threshold_values)
# thru_filt_test = [copy.deepcopy(s2p_files[1])]
# s2p_filt = fourier_filter(thru_filt_test, threshold = threshold_values)
# pristine_filt_test = [copy.deepcopy(s2p_files[24])]
# s2p_filt = fourier_filter(pristine_filt_test, threshold = threshold_values)
# ## Step 1 - fourier filter the initial files to remove noise
# s2p_filt = copy.deepcopy(s2p_files)
# s2p_filt = fourier_filter(s2p_filt, threshold = threshold_values) #apply to deepcopy to avoid modifying the original data
# # Step 2 - check a fourier deconvolution of all the thru data
# cal_thru = [s for s in s2p_filt if s.state == 'thru' and s.wafer_number != 0]
# s2p_filt_convolve = copy.deepcopy(s2p_files)
# s2p_filt_convolve = fourier_convolve(s2p_filt_convolve, cal_thru) #apply to deepcopy to avoid modifying the original data
# # Step 3 - what about a time domain deconvolution??
# cal_thru = [s for s in s2p_filt if s.state == 'thru' and s.wafer_number != 0]
# s2p_filt_inverse = copy.deepcopy(s2p_files)
# s2p_filt_inverse = fourier_inverse(s2p_filt_inverse, cal_thru) #apply to deepcopy to avoid modifying the original data
# # Group files by their state so I can plot and compare states
# pristine = [s for s in s2p_filt if s.state == 'pristine']
# formed = [s for s in s2p_filt if s.state in ['formed', 'smallform', 'fullform']]
# # Group files with the same [r_number, c_number] values together so I can plot each device in all its states on one graph
# # Stores a list of S2PFile objects for each device in a dictionary, "dev", with the key being the device's [r_number, c_number] values
# #thus dev['11'] will have all the data for the device in row 1 column 1
# dev = {}
# for s in s2p_files:
# key = f"r{s.dev_row}c{s.dev_col}"
# if key in dev:
# dev[key].append(s)
# else:
# dev[key] = [s]
# #-------------------Subsetting-------------------
# #dev_subs = subgen(s2p_files, run_nums =[[1,2,3,4,5,6], [31,27,23,35,39,41], [47,42,50] ] )
# #dev_subs_filt = subgen(s2p_filt, run_nums =[[1,2,3,4,5,6], [31,27,23,35,39,41], [47,42,50] ] )
# #dev_subs = subgen(s2p_files, run_nums =[[1,2], [23], [42] ] )
# dev_subs = subgen(s2p_files, run_nums =[[1,2,3,4,5,6], [56,60,64,67], [57,58,59,61,62,63,65,66,68] ] )
# dev_subs_filt = subgen(s2p_filt, run_nums =[[1,2,3,4,5,6], [56,60,64,67], [57,58,59,61,62,63,65,66,68] ] )
# dev_subs_convolve = subgen(s2p_filt_convolve, run_nums =[[1,2,3,4,5,6], [56,60,64,67], [57,58,59,61,62,63,65,66,68] ] )
# dev_subs_inverse = subgen(s2p_filt_inverse, run_nums =[[1,2,3,4,5,6], [56,60,64,67], [57,58,59,61,62,63,65,66,68] ] )
# #-------------------Plotting-------------------
# #def keyplot(OS, dev, dev_selection = None, sub_set = [], y_range = None,
# # x_range = slice(0,-1), log_x = False, plot_type = 'S_db',m_port=[2], n_port=[1]):
# #'inputz' - plots the input impedance of the device
# x_range_input = "0.02-20ghz"#slice(0,-1)#"0.02-0.8ghz" #
# y_range_input = None#[0,200]#None#[0,200]
# # def subplot(dev_subs = [], cal_in = [], y_range = None,
# # x_range = slice(0,-1), log_x = False, plot_type = 'S_db',m_port=[2], n_port=[1], deembed_data = True):
# # def subgen(s2p_files, run_nums = [[],[],[]]):
# # fig1 = subplot(dev_subs = dev_subs, cal_in = OS, plot_type = ['power', 'inputz', 'S_db'],
# # log_x=False, m_port=[2], n_port=[1],deembed_data = True, y_range=y_range_input, x_range=x_range_input)
# # fig2 = subplot(dev_subs = dev_subs, cal_in = OS, plot_type = ['power', 'inputz', 'S_db'],
# # log_x=False, m_port=[2], n_port=[1],deembed_data = False, y_range=y_range_input)
# # fig3 = subplot(dev_subs = dev_subs_filt, cal_in = TX, plot_type = ['s_mag','s_deg'],
# # log_x=False, m_port=[2], n_port=[1],deembed_data = True, y_range=y_range_input, x_range=x_range_input)
# # fig3 = subplot(dev_subs = dev_subs_filt, cal_in = OS, plot_type = ['s_mag','s_deg'],
# # log_x=False, m_port=[2], n_port=[1],deembed_data = True, y_range=y_range_input, x_range=x_range_input)
# fig4 = subplot(dev_subset = dev_subs, cal_in = OS, plot_type = ['s_mag'],
# log_x=False, m_port=[2], n_port=[1],deembed_data = False, y_range=y_range_input, x_range=x_range_input)
# fig4 = subplot(dev_subset = dev_subs_filt, cal_in = OS, plot_type = ['s_mag'],
# log_x=False, m_port=[2], n_port=[1],deembed_data = False, y_range=y_range_input, x_range=x_range_input)
# fig4 = subplot(dev_subset = dev_subs_convolve, cal_in = OS, plot_type = ['s_mag'],
# log_x=False, m_port=[2], n_port=[1],deembed_data = False, y_range=y_range_input, x_range=x_range_input)
# fig5 = subplot(dev_subset = dev_subs_inverse, cal_in = OS, plot_type = ['s_mag'],
# log_x=False, m_port=[2], n_port=[1],deembed_data = False, y_range=y_range_input, x_range=x_range_input)
# plt.show()
In [ ]:
#-------------------Network Set-------------------
#takes a dictionary or list of networks as its input and converts to a network set object that can give errors etc for repeated measurements
# Convert the dev dictionary of lists of s2p files into a dictionary of lists of networks
#need filtering, probably taken from the keyplot function to select the devices and states to include in the network set
# probably actually just want to make this another keyplot function that takes the network set as an input and then plots the data
# dev_networks = {}
# for key, value in dev.items():
# dev_networks[key] = [s.network for s in value]
# ro_ns = NetworkSet(dev_networks, name='ro set')